package com.smedi.ismedi.authoritymanagement.core.application.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.smedi.ismedi.authoritymanagement.core.application.command.*;
import com.smedi.ismedi.authoritymanagement.core.application.convert.AppConverter;
import com.smedi.ismedi.authoritymanagement.core.application.query.ElementQueryService;
import com.smedi.ismedi.authoritymanagement.core.application.service.ElementApplicationService;
import com.smedi.ismedi.authoritymanagement.core.domain.aggregatemodel.Element;
import com.smedi.ismedi.authoritymanagement.core.domain.dto.ElementQuery;
import com.smedi.ismedi.authoritymanagement.core.domain.service.ElementDomainService;
import com.smedi.ismedi.authoritymanagement.core.port.adapter.persistence.model.RoleElementRelationshipEntity;
import com.smedi.ismedi.authoritymanagement.core.port.adapter.persistence.mybatis.mapper.RoleElementRelationshipMapper;
import com.smedi.ismedi.cache.starter.util.RedisUtil;
import com.smedi.ismedi.web.starter.config.AsyncThreadPoolConfig;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

import static com.smedi.ismedi.authoritymanagement.core.infrastructure.constant.ConstantField.COLONS;
import static com.smedi.ismedi.authoritymanagement.core.infrastructure.constant.ConstantField.TOKEN_EFFECTIVE_TIME;

/**
 * 特种设备应用服务实现类
 *
 * @author xienannan
 * @date 2021/08/28
 */
@Service
@RequiredArgsConstructor
@Transactional
public class ElementApplicationServiceImpl implements ElementApplicationService {
    private final ElementDomainService elementDomainService;
    private final ElementQueryService elementQueryService;
    private final AppConverter appConverter;
    private final AsyncThreadPoolConfig asyncThreadPoolConfig;
    private final RedisUtil redisUtil;

    private final RoleElementRelationshipMapper roleElementRelationshipMapper;

    @Override
    public Element createElement(ElementCreateCommand elementCreateCommand) {
        //       this.validKey(elementCreateCommand.getBusinessToken());

        Element element = appConverter.elementCreateCommandToElement(elementCreateCommand);

        return elementDomainService.createElement(element);
    }

    @Override
    public Element editElement(ElementEditCommand elementEditCommand) {
        Element elementUpdated;

        String editElementLockKey = "editElement" + COLONS + "elementId" + COLONS + elementEditCommand.getId();

        if (redisUtil.incr(editElementLockKey, 1) != 1) {
            return null;
        }

        try {
            Element element = elementQueryService.getElementOne(ElementOneQuery.builder().id(elementEditCommand.getId()).build());
            Element elementEdited = appConverter.updateElementByElementEditCommand(element, elementEditCommand);
            elementUpdated = elementDomainService.updateElement(elementEdited);
        } finally {
            redisUtil.set(editElementLockKey, 0, TOKEN_EFFECTIVE_TIME);
        }

        return elementUpdated;
    }

    @Override
    public void editElement(List<ElementEditCommand> elementEditCommands) {
        for (ElementEditCommand elementEditCommand : elementEditCommands) {
            asyncThreadPoolConfig.taskExecutor().execute(() -> {
                        this.editElement(elementEditCommand);
                    }
            );
        }
    }

    @Override
    public void removeElement(ElementRemoveCommand elementRemoveCommand) {
        ElementQuery elementQuery = appConverter.elementRemoveCommandToElementQuery(elementRemoveCommand);
        elementDomainService.removeElement(elementQuery);
    }

    @Override
    public void saveRoleElementRelationship(RoleElementRelationshipSaveCommand roleElementRelationshipSaveCommand) {
        String saveRoleElementRelationshipLockKey = "saveRoleElementRelationship" + COLONS + "roleId" + COLONS + roleElementRelationshipSaveCommand.getRoleId();

        if (redisUtil.incr(saveRoleElementRelationshipLockKey, 1) != 1) {
            return;
        }
        try {
            // 先删除
            LambdaQueryWrapper<RoleElementRelationshipEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(RoleElementRelationshipEntity::getRoleId, roleElementRelationshipSaveCommand.getRoleId());
            roleElementRelationshipMapper.delete(lambdaQueryWrapper);

            // 再批量新增
            List<RoleElementRelationshipEntity> roleElementRelationshipEntities = new ArrayList<>();
            for (Long elementId : roleElementRelationshipSaveCommand.getElementIds()) {
                roleElementRelationshipEntities.add(RoleElementRelationshipEntity.builder().roleId(roleElementRelationshipSaveCommand.getRoleId()).elementId(elementId).build());
            }
            roleElementRelationshipMapper.insertBatch(roleElementRelationshipEntities);
        } finally {
            redisUtil.set(saveRoleElementRelationshipLockKey, 0, TOKEN_EFFECTIVE_TIME);
        }
    }
}
